﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NLite
{
	/// <summary>
	/// 
	/// </summary>
	public struct Result
	{
		/// <summary>
		/// 
		/// </summary>
		public static Result OK { get; private set; }

		private readonly Exception exception;
		private readonly bool success;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="success"></param>
		/// <param name="ex"></param>
		public Result(bool success, Exception ex)
		{
			this.success = success;
			this.exception = ex;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="handler"></param>
		/// <returns></returns>
		public Result Exception(Action<Exception> handler)
		{
			if (!this.success)
				handler(this.exception);
			return this;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="handler"></param>
		/// <returns></returns>
		public Result Success(Action handler)
		{
			if (this.success)
			{
				handler();
			}
			return this;
		}

		static Result()
		{
			OK = new Result(true, null);
		}
	}

	/// <summary>
	/// 
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public struct Result<T>
	{
		private readonly Exception exception;
		private readonly bool success;
		private readonly T parameter;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="success"></param>
		/// <param name="ex"></param>
		/// <param name="param"></param>
		public Result(bool success, Exception ex, T param)
		{
			this.success = success;
			this.parameter = param;
			this.exception = success ? null : ex;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="handler"></param>
		/// <returns></returns>
		public Result<T> Exception(Action<Exception> handler)
		{
			if (!this.success)
				handler(this.exception);
			return this;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="handler"></param>
		/// <returns></returns>
		public Result<T> Success(Action<T> handler)
		{
			if (this.success)
				handler(this.parameter);
			return this;
		}


	}
	
	/// <summary>
	/// Combines a boolean succes/fail flag with a error/status message.
	/// </summary>
	[Serializable]
	public class BoolMessage
	{
		

		/// <summary>
		/// Success / failure ?
		/// </summary>
		public readonly bool Success;

		/// <summary>
		/// Error message for failure, status message for success.
		/// </summary>
		public readonly string Message;
		
		/// <summary>
		/// 
		/// </summary>
		public virtual object Data { get;private set;}
		/// <summary>
		/// 
		/// </summary>
		public Exception Exception { get;private set;}


		/// <summary>
		/// Set the readonly fields.
		/// </summary>
		/// <param name="success"></param>
		/// <param name="message"></param>
		protected BoolMessage(bool success, string message, Exception exception, object data)
		{
			Success = success;
			Message = message;
			Exception = exception;
			Data = data;
		}
		
		/// <summary>
		/// 
		/// </summary>
		/// <param name="message"></param>
		/// <param name="data"></param>
		/// <returns></returns>
		public static BoolMessage True(string message,object data)
		{
			return new BoolMessage(true,message,null,data);
		}
		
		public static BoolMessage True(string message)
		{
			return new BoolMessage(true,message,null,null);
		}
		
		public static BoolMessage True()
		{
			return new BoolMessage(true,null,null,null);
		}
		
		/// <summary>
		/// 
		/// </summary>
		/// <param name="message"></param>
		/// <param name="exception"></param>
		/// <param name="data"></param>
		/// <returns></returns>
		public static BoolMessage False(string message,Exception exception, object data)
		{
			return new BoolMessage(false,message,exception,data);
		}
		
		public static BoolMessage False(string message)
		{
			return new BoolMessage(false,message,null,null);
		}
		
		public static BoolMessage False()
		{
			return new BoolMessage(false,null,null,null);
		}
		
		/// <summary>
		/// 
		/// </summary>
		/// <param name="message"></param>
		/// <param name="data"></param>
		/// <returns></returns>
		public static BoolMessage<TData> True<TData>(string message,TData data)
		{
			return new BoolMessage<TData>(true,message,null,data);
		}
		
		public static BoolMessage<TData> True<TData>(TData data)
		{
			return new BoolMessage<TData>(true,null,null,data);
		}
		
		
		/// <summary>
		/// 
		/// </summary>
		/// <param name="message"></param>
		/// <param name="exception"></param>
		/// <param name="data"></param>
		/// <returns></returns>
		public static BoolMessage<TData> False<TData>(string message,Exception exception, TData data)
		{
			return new BoolMessage<TData>(false,message,exception,data);
		}
		
		public static BoolMessage<TData> False<TData>(string message,Exception exception)
		{
			return new BoolMessage<TData>(false,message,exception,default(TData));
		}
		
		public static BoolMessage<TData> False<TData>(string message)
		{
			return new BoolMessage<TData>(false,message,null,default(TData));
		}
	}
	
	[Serializable]
	public class BoolMessage<TData>:BoolMessage
	{
		protected internal BoolMessage(bool success, string message, Exception exception, object data):base(success,message,exception,data)
		{
		}
		public new TData Data { get{ return (TData)base.Data;}}
	}

}
